package com.gulimall.order.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gulimall.common.constrant.OrderConstant;
import com.gulimall.common.enums.OrderStatusEnum;
import com.gulimall.common.to.WareSkuLockTo;
import com.gulimall.common.to.rabbit.SekcillOrderTo;
import com.gulimall.common.utils.PageUtils;
import com.gulimall.common.utils.Query;
import com.gulimall.common.utils.R;
import com.gulimall.common.vo.MemberRespVo;
import com.gulimall.order.dao.OrderDao;
import com.gulimall.order.entity.OrderEntity;
import com.gulimall.order.entity.OrderItemEntity;
import com.gulimall.order.feign.CartFeignService;
import com.gulimall.order.feign.MemberFeignService;
import com.gulimall.order.feign.ProductFeignService;
import com.gulimall.order.feign.WareFeignService;
import com.gulimall.order.interceptor.OrderInterceptor;
import com.gulimall.order.service.OrderItemService;
import com.gulimall.order.service.OrderService;
import com.gulimall.order.to.OrderProductSpuTo;
import com.gulimall.order.vo.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    @Autowired
    private MemberFeignService memberFeignService;
    @Autowired
    private CartFeignService cartFeignService;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    private WareFeignService wareFeignService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(new Query<OrderEntity>().getPage(params), new QueryWrapper<OrderEntity>());

        return new PageUtils(page);
    }

    /**
     * 返回订单页所需的数据
     *
     * @return
     */
    @Override
    public OrderConfirmVo confirmOrder() {
        OrderConfirmVo confirmVo = new OrderConfirmVo();
        MemberRespVo memberRespVo = OrderInterceptor.THREAD_LOCAL.get();

        //由于异步编排 开了两个新线程，不能获取当前线程的ThreadLocal信息，故手动给新线程加上ThreadLocal信息
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        CompletableFuture<Void> memberFuture = CompletableFuture.runAsync(() -> {
            //给当前新线程加上ThreadLocal信息
            RequestContextHolder.setRequestAttributes(requestAttributes);

            //1.远程查询所有的收货地址集合
            R addressResult = memberFeignService.getUserAddress(memberRespVo.getId());
            if (addressResult.getResult() == 0) {
                String addressJson = (String) addressResult.get("addressList");
                List<JSONObject> addressListJson = JSONObject.parseObject(addressJson, List.class);
                List<MemberAddressVo> addressList = addressListJson.stream().map(item -> {
                    MemberAddressVo to = item.to(new TypeReference<MemberAddressVo>() {
                    });
                    return to;
                }).collect(Collectors.toList());
                if (addressList.size() > 0) {
                    confirmVo.setAddress(addressList);
                }
            } else {
                log.error("远程调用查询收货地址异常 " + addressResult.toString());
            }
        }, threadPoolExecutor);

        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            //给当前新线程加上ThreadLocal信息
            RequestContextHolder.setRequestAttributes(requestAttributes);

            //2.远程查询购物车中选中的项
            R cartResult = cartFeignService.getCartCheckItem();
            if (cartResult.getResult() == 0) {
                String cartJson = (String) cartResult.get("cartItems");
                List<JSONObject> cartListJson = JSONObject.parseObject(cartJson, List.class);
                List<OrderItemVo> cartItems = cartListJson.stream().map(item -> {
                    OrderItemVo orderItemVo = item.to(new TypeReference<OrderItemVo>() {
                    });
                    return orderItemVo;
                }).collect(Collectors.toList());
                if (cartItems.size() > 0) {
                    confirmVo.setItems(cartItems);
                }
            } else {
                log.error("远程调用查询购物车异常 " + cartResult.toString());
            }
        }, threadPoolExecutor);

        //查询商品的库存信息
        CompletableFuture<Void> stockFuture = cartFuture.thenAcceptAsync((res) -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);

            List<Long> skuIds = confirmVo.getItems().stream().map(OrderItemVo::getSkuId).collect(Collectors.toList());
            R stockResult = wareFeignService.getStockBySkuId(skuIds);
            if (stockResult.getResult() == 0) {
                Map<String, Boolean> stockMap = (Map<String, Boolean>) stockResult.get("stocks");
                for (OrderItemVo item : confirmVo.getItems()) {
                    item.setHasStock(stockMap.get(item.getSkuId().toString()));
                }
            } else {
                log.error("远程调用查询购物车异常 " + stockResult.toString());
            }
        }, threadPoolExecutor);

        //3.查询用户积分
        confirmVo.setIntegration(memberRespVo.getIntegration());

        //4.其他数据自动计算

        //TODO 5.防重令牌
        String token = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId(), token, 30,
                TimeUnit.MINUTES);
        confirmVo.setOrderToken(token);

        try {
            CompletableFuture.allOf(memberFuture, cartFuture, stockFuture).get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

        return confirmVo;
    }

    //    @GlobalTransactional
    @Override
    @Transactional
    public OrderSubmitResponseVo submitOrder(OrderSubmitVo orderSubmitVo) {
        OrderSubmitResponseVo responseVo = new OrderSubmitResponseVo();
        responseVo.setCode(0);

        MemberRespVo memberRespVo = OrderInterceptor.THREAD_LOCAL.get();
        //1.验证令牌 令牌的比对必须保证原子性
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return "
                + "0 end";
        Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
                List.of(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId()), orderSubmitVo.getOrderToken());

        if (result == 0L) {
            //验证失败
            responseVo.setCode(1);
            return responseVo;
        } else {
            //1.验证成功 创建订单信息
            OrderCreateTo order = createOrder(orderSubmitVo);

            //2.验价
            BigDecimal payPrice = orderSubmitVo.getPayPrice();
            BigDecimal productPrice = order.getPayPrice();
            if (Math.abs(payPrice.subtract(productPrice).doubleValue()) < 0.01) {
                //3. 保存订单
                saveOrder(order);

                //4.库存锁定
                WareSkuLockTo wareSkuLockTo = new WareSkuLockTo();
                wareSkuLockTo.setOrderSn(order.getOrder().getOrderSn());
                List<WareSkuLockTo.skuItem> skuItemList = order.getOrderItems().stream().map(item -> {
                    WareSkuLockTo.skuItem skuItem = new WareSkuLockTo.skuItem();
                    skuItem.setSkuId(item.getSkuId());
                    skuItem.setCount(item.getSkuQuantity());
                    skuItem.setSkuName(item.getSkuName());
                    return skuItem;
                }).collect(Collectors.toList());
                wareSkuLockTo.setSkuItems(skuItemList);

                R wareLockResult = wareFeignService.orderLockStock(wareSkuLockTo);
                if (wareLockResult.getResult() == 0) {
                    responseVo.setOrder(order.getOrder());
//                    int a = 10 / 0;
                    //订单提交全部完成后，将消息放到消息队列中，一定时间后，订单状态如果为’已创建’ 就将库存恢复
                    rabbitTemplate.convertAndSend(OrderConstant.ORDER_EVENT_EXCHANGE, OrderConstant.CREATE_ORDER_KEY,
                            order.getOrder());
                    return responseVo;
                } else {
                    log.error("调用库存锁定异常 " + wareLockResult);
                    responseVo.setCode(3);
                    return responseVo;
                }
            } else {
                responseVo.setCode(2);
                return responseVo;
            }
        }
    }

    /**
     * 一定时间，如果订单状态未改变，应当恢复库存
     *
     * @param order
     */
    @Override
    public void orderClose(OrderEntity order) {
        String orderSn = order.getOrderSn();
        OrderEntity orderEntity = getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        if (orderEntity.getStatus().equals(OrderStatusEnum.CREATE_NEW.getCode())) {
            OrderEntity update = new OrderEntity();
            update.setId(order.getId());
            update.setStatus(OrderStatusEnum.CANCLED.getCode());
            updateById(update);

            //应当向消息队列发一条消息，来告诉库存系统解锁，避免因为网络延迟造成库存无法自动解锁
            rabbitTemplate.convertAndSend(OrderConstant.ORDER_EVENT_EXCHANGE, "order.release.other.close", orderSn);
        }
    }

    @Override
    public PayVo getOrderInfo(String orderSn) {
        PayVo payVo = new PayVo();
        OrderEntity orderEntity = getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        List<OrderItemEntity> itemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn",
                orderSn));

        payVo.setOut_trade_no(orderSn);
        payVo.setTotal_amount(orderEntity.getPayAmount().setScale(2).toString());
        payVo.setSubject(itemEntities.get(0).getSkuName());

        return payVo;
    }

    /**
     * 查询当前登录用户的订单
     *
     * @param params
     * @return
     */
    @Override
    public PageUtils getOrderList(Map<String, Object> params) {
        MemberRespVo memberRespVo = OrderInterceptor.THREAD_LOCAL.get();

        Page<OrderEntity> entityPage = this.page(new Page<OrderEntity>(), new QueryWrapper<OrderEntity>().eq(
                "member_id", memberRespVo.getId()).orderByDesc("create_time"));
        List<OrderEntity> entityPageRecords = entityPage.getRecords();
        for (OrderEntity orderEntity : entityPageRecords) {
            List<OrderItemEntity> itemEntityList = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq(
                    "order_sn", orderEntity.getOrderSn()));
            orderEntity.setOrderItems(itemEntityList);
        }
        entityPage.setRecords(entityPageRecords);

        return new PageUtils(entityPage);
    }

    @Override
    public void saveSeckillOrder(SekcillOrderTo sekcillOrderTo) {
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(sekcillOrderTo.getOrderSn());
        orderEntity.setMemberId(sekcillOrderTo.getMemberId());
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        BigDecimal totalPrice = sekcillOrderTo.getSeckillPrice().multiply(new BigDecimal(sekcillOrderTo.getCount()));
        orderEntity.setTotalAmount(totalPrice);
        orderEntity.setPayAmount(totalPrice);

        save(orderEntity);
    }

    private void saveOrder(OrderCreateTo orderCreateTo) {
        OrderEntity order = orderCreateTo.getOrder();
        List<OrderItemEntity> orderItems = orderCreateTo.getOrderItems();

        save(order);
        orderItemService.saveBatch(orderItems);
    }

    /**
     * 创建订单
     *
     * @return
     */
    private OrderCreateTo createOrder(OrderSubmitVo orderSubmitVo) {
        OrderCreateTo orderCreateTo = new OrderCreateTo();
        //1.生成订单信息
        OrderEntity orderEntity = createOrderEntity(orderSubmitVo);
        orderCreateTo.setOrder(orderEntity);

        //2.生成订单项信息
        List<OrderItemEntity> orderItems = createOrderItems(orderEntity);
        orderCreateTo.setOrderItems(orderItems);

        //3.设置价格信息
        setOrderPrice(orderCreateTo);

        return orderCreateTo;
    }

    /**
     * 设置价格信息
     */
    private void setOrderPrice(OrderCreateTo orderCreateTo) {
        OrderEntity order = orderCreateTo.getOrder();
        List<OrderItemEntity> orderItems = orderCreateTo.getOrderItems();
        BigDecimal totalPrice = new BigDecimal("0");
        for (OrderItemEntity orderItem : orderItems) {
            totalPrice = totalPrice.add(orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuQuantity())));
        }

        order.setTotalAmount(totalPrice);
        order.setPayAmount(totalPrice);
        order.setIntegration(totalPrice.intValue());
        order.setGrowth(totalPrice.intValue());
        order.setModifyTime(new Date());
        orderCreateTo.setPayPrice(totalPrice);
    }

    /**
     * 生成订单信息
     */
    private OrderEntity createOrderEntity(OrderSubmitVo orderSubmitVo) {
        String orderSn = IdWorker.getTimeId();
        //创建订单号
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(orderSn);

        //远程调用查询收货地址信息
        R info = memberFeignService.info(orderSubmitVo.getAddressId());
        if (info.getResult() == 0) {
            MemberAddressVo memberReceiveAddress = JSONObject.parseObject(JSONObject.toJSONString(info.get(
                    "memberReceiveAddress")), MemberAddressVo.class);
            //给订单设置收货信息
            orderEntity.setReceiverCity(memberReceiveAddress.getCity());
            orderEntity.setReceiverDetailAddress(memberReceiveAddress.getDetailAddress());
            orderEntity.setReceiverName(memberReceiveAddress.getName());
            orderEntity.setReceiverPhone(memberReceiveAddress.getPhone());
            orderEntity.setReceiverPostCode(memberReceiveAddress.getPostCode());
            orderEntity.setReceiverProvince(memberReceiveAddress.getProvince());
            orderEntity.setReceiverRegion(memberReceiveAddress.getRegion());
        } else {
            log.error("远程调用查询收货地址信息 异常 " + info);
        }

        //设置账户信息
        MemberRespVo memberRespVo = OrderInterceptor.THREAD_LOCAL.get();
        orderEntity.setMemberId(memberRespVo.getId());
        orderEntity.setMemberUsername(memberRespVo.getUsername());

        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        orderEntity.setPayType(orderSubmitVo.getPayType());
        orderEntity.setCreateTime(new Date());

        return orderEntity;
    }

    /**
     * 生成订单项信息
     */
    public List<OrderItemEntity> createOrderItems(OrderEntity order) {
        List<OrderItemEntity> itemEntities = new ArrayList<>();
        List<OrderItemVo> orderItemVos = new ArrayList<>();
        //调用远程服务获取选中商品
        R checkItemResult = cartFeignService.getCartCheckItem();
        if (checkItemResult.getResult() == 0) {
            List<JSONObject> cartItemList = JSONObject.parseObject((String) checkItemResult.get("cartItems"),
                    List.class);
            orderItemVos.addAll(cartItemList.stream().map(item -> {
                OrderItemVo orderItemVo = item.to(new TypeReference<OrderItemVo>() {
                });
                return orderItemVo;
            }).collect(Collectors.toList()));
        } else {
            log.error("调用远程服务获取选中商品 异常 " + checkItemResult);
        }

        List<Long> skuIds = orderItemVos.stream().map(OrderItemVo::getSkuId).collect(Collectors.toList());
        Map<Long, BigDecimal> priceMap = new HashMap<>();

        //查询商品最新价格
        R priceResult = productFeignService.querySkuPrice(skuIds);
        if (priceResult.getResult() == 0) {
            Map<String, Double> pricesMap = (Map<String, Double>) priceResult.get("pricesMap");
            for (Map.Entry<String, Double> entry : pricesMap.entrySet()) {
                priceMap.put(Long.parseLong(entry.getKey()), BigDecimal.valueOf(entry.getValue()));
            }
        } else {
            log.error("调用远程查询价格异常 " + priceResult);
        }

        Map<Long, OrderProductSpuTo> productSpuToMap = new HashMap<>();
        //根据skuId远程查询spu 信息
        R spuInfoResult = productFeignService.findSpuBySkuIds(skuIds);
        if (spuInfoResult.getResult() == 0) {
            Map<String, String> spuInfoMap = JSONObject.parseObject(String.valueOf(spuInfoResult.get("spuList")),
                    Map.class);

            for (Map.Entry<String, String> entry : spuInfoMap.entrySet()) {
                productSpuToMap.put(Long.parseLong(entry.getKey()), JSONObject.parseObject(entry.getValue(),
                        OrderProductSpuTo.class));
            }

        } else {
            log.error("根据skuId远程查询spu 信息 异常 " + spuInfoResult);
        }

        for (OrderItemVo orderItemVo : orderItemVos) {
            itemEntities.add(getOrderItem(orderItemVo, productSpuToMap.get(orderItemVo.getSkuId()), order,
                    priceMap.get(orderItemVo.getSkuId())));
        }

        return itemEntities;
    }

    /**
     * 生成购物项的每一项
     */
    public OrderItemEntity getOrderItem(OrderItemVo orderItemVo, OrderProductSpuTo orderProductSpuTo,
                                        OrderEntity order, BigDecimal newPrice) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setOrderSn(order.getOrderSn());
        orderItemEntity.setOrderId(order.getId());
        //设置spu信息
        orderItemEntity.setCategoryId(orderProductSpuTo.getCatalogId());
        orderItemEntity.setSpuId(orderProductSpuTo.getId());
        orderItemEntity.setSpuName(orderProductSpuTo.getSpuName());
        orderItemEntity.setSpuBrand(orderProductSpuTo.getBrandId().toString());

        //设置sku信息
        orderItemEntity.setSkuId(orderItemVo.getSkuId());
        orderItemEntity.setSkuName(orderItemVo.getTitle());
        orderItemEntity.setSkuPrice(newPrice);
        orderItemEntity.setSkuQuantity(orderItemVo.getCount());
        orderItemEntity.setSkuPic(orderItemVo.getImage());
        orderItemEntity.setSkuAttrsVals(JSONObject.toJSONString(orderItemVo.getSkuAttr()));

        //赠送积分
        orderItemEntity.setGiftIntegration(newPrice.intValue());
        orderItemEntity.setGiftGrowth(newPrice.intValue());

        return orderItemEntity;
    }
}
